#pragma once
#ifndef OBR_TEXTURE_H
#define OBR_TEXTURE_H

#include "SharedDS/TextureDS.h"
#include "common.h"
#include "CudaBuffer.h"
#include "helpers/Helpers.h"

namespace OBR
{
template <typename DataType, int dim> class Texture
{
public:
    bool initialized = false;
    uint size[dim];
    DataType *data = nullptr;

private:
    CudaBuffer d_texture_data;

public:
    Texture();
    Texture(DataType default_value);
    Texture(const Texture<DataType, dim> &tex);
    ~Texture();

    /**
     * @brief assignment operator for texture
     *
     * @param src
     * @return Texture<DataType, dim>&
     */
    Texture<DataType, dim> &operator=(const Texture<DataType, dim> &src);

    /**
     * @brief get element from texture, maximun of 3 dimentions
     *
     * @param x
     * @param y
     * @param z
     * @return DataType&
     */
    DataType &at(uint x, uint y = 0, uint z = 0);

    /**
     * @brief load data
     *
     * @param _size
     * @param _data
     */
    void load(uint *_size, DataType *_data);

    /**
     * @brief upload data inside this->data & size to device
     *
     */
    void upload();

    /**
     * @brief get DeviceTexture2D object with proper device memory layout
     *
     * @return DeviceTexture2D<DataType>
     */
    DeviceTexture2D<DataType> getDeviceTex2D();

    /**
     * @brief get DeviceTexture3D object with proper device memory layout
     *
     * @return DeviceTexture3D<DataType>
     */
    DeviceTexture3D<DataType> getDeviceTex3D();
};

typedef Texture<Spectrum, 2> ColorTexture2D;
typedef Texture<Spectrum, 3> ColorTextuer3D;
typedef Texture<float, 2> FloatTexture2D;
typedef Texture<float, 3> FloatTextuer3D;

} // namespace OBR

#endif